package com.ruoyi.framework.web.service;

import com.alibaba.fastjson.JSON;
import com.ruoyi.common.config.Global;
import com.ruoyi.common.config.RedisConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.redis.RedisClientUtil;
import com.ruoyi.common.utils.Base64Util;
import com.ruoyi.common.utils.CryptUtils;
import com.ruoyi.common.utils.MD5Util;
import com.ruoyi.common.utils.SortMap;
import com.ruoyi.framework.filter.RequestWrapper;
import com.ruoyi.framework.interceptor.RequestType;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * API 拦截器 调用的处理类
 * 完成 ACCESS_TOKEN 、 SIGN（签名） 等权限验证
 * 其他业务方法不要写在此类下
 *
 * @author shihx
 * @date 2019/7/10 16:20
 * @return
 */
@Service
public class SystemApiServiceImpl {

    private static final Log log = LogFactory.getLog(SystemApiServiceImpl.class);

    /**
     * 读取guoruan配置文件信息
     */
    @Autowired
    Global guoRuanConfig;

    /**
     * 注入redis客户端
     */
    @Autowired
    RedisConfig redisConfig;

    /**
     * API拦截器 验证ACCESS_TOKEN
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param object
     * @return
     * @date 2019/7/10 16:39
     * @author shihx
     */
    public boolean AccessTokenRequired(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) {

        log.info("进入 ACCESS_TOKEN 验证方法");
        /** AccessToken令牌 */
        String AccessToken = "";

        /** 获取Header头里面的信息 */
        Enumeration headerNames = httpServletRequest.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            if ("token".equals(key)) {
                AccessToken = httpServletRequest.getHeader(key);
                continue;
            }
        }

        log.info("Header参数：AccessToken=：" + AccessToken);

        /** 验证access token不为空不为null */
        if (StringUtils.isNotEmpty(AccessToken)) {
            //初始化redis
            RedisClientUtil.getInstance().initialPool(redisConfig.getIp(), redisConfig.getPort(), redisConfig.getPassword(), redisConfig.getTimeout());
            Jedis redis = RedisClientUtil.getInstance().getJedis();
            if (StringUtils.isNotEmpty(redis.get(AccessToken))) {
//                redis.expire(AccessToken, Constants.ACCESS_TOKEN_TIMES);
//
//                //更新缓存失效时间 20200606
//                String ApiKey = redis.get(AccessToken);
//                if (StringUtils.isNotEmpty(redis.get(ApiKey))) {
//                    redis.expire(ApiKey, Constants.ACCESS_TOKEN_TIMES);
//                }
                return true;
            }
        }
        log.info("AccessToken----------------"+AccessToken+"------------------------校验失败");
        return false;
    }

    /**
     * API拦截器 Sign 签名验证
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param object
     * @return
     * @date 2019/7/10 16:40
     * @author shihx
     */
    public boolean SignRequired(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) {

        log.info("进入 SIGN 签名 验证方法");

        /** 加密串 */
        String sign = "";
        /** 时间戳 */
        Long timestamp = 0L;
        /** Content-Type */
        String contentType = "";

        /** 获取Header头里面的信息 */
        Enumeration headerNames = httpServletRequest.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            if ("sign".equals(key)) {
                sign = httpServletRequest.getHeader(key);
                continue;
            }
            if ("timestamp".equals(key)) {
                timestamp = Long.parseLong(httpServletRequest.getHeader(key));
                continue;
            }
            if ("content-type".equals(key)) {
                contentType = httpServletRequest.getHeader(key);
                continue;
            }
        }

        log.info("Header参数：加密串=：" + sign + " 时间戳=：" + timestamp);

        /** 如果sign 参数为空 或 timestamp 参数为0 直接返回 false */
        if (StringUtils.isEmpty(sign) || timestamp == 0) {
            return false;
        }

        /** 获取API接口地址时效性 */
        Long second = Long.parseLong(guoRuanConfig.getTimestamp());

        /** 获取系统时间戳 */
        Long serverTimestamp = System.currentTimeMillis();

        /** 如果API接口传过来的时间戳 大于接口地址的时效性 直接返回 false */
        if ((serverTimestamp - timestamp) > second) {
            return false;
        }

        /** 获得过来的请求是GET还是POST */
        String reqmethod = httpServletRequest.getMethod();
        /** 如果是GET按照get方式进行加密验证 */
        if (RequestType.GET.equalsIgnoreCase(reqmethod)) {
            Enumeration em = httpServletRequest.getParameterNames();
            if (em != null) {
                SortedMap<String, Object> params = new TreeMap<String, Object>();
                //遍历参数集
                while (em.hasMoreElements()) {
                    String name = (String) em.nextElement();
                    String value = httpServletRequest.getParameter(name);
                    params.put(name, value);
                }

                log.info("Get参数：" + params.toString());

                /** 生成服务端签名 */
                String serverSign = GenerateSignature(params, timestamp);

                /** 如果客户端的签名 和 服务端的签名一致 则验证通过 */
                if (serverSign.equals(sign)) {
                    return true;
                }
            }
        }
        /** 如果是POST按照post方式进行加密验证 */
        if (RequestType.POST.equalsIgnoreCase(reqmethod)) {
            RequestWrapper requestWrapper = new RequestWrapper(httpServletRequest);
            String body = requestWrapper.getBody();

            /** 把 POST 参数 JSON 转 Map */
            Map params = new HashMap();

            if (contentType.contains("multipart/form-data")) {
                params = new HashMap();
                Enumeration<String> parameterNames = requestWrapper.getRequest().getParameterNames();
                if (null != parameterNames) {
                    while(parameterNames.hasMoreElements()){
                        String key = parameterNames.nextElement();
                        String value = requestWrapper.getRequest().getParameter(key)+"";
                        if(StringUtils.isNotEmpty(value)){
                            params.put(key,requestWrapper.getRequest().getParameter(key));
                        }
                    }
                }

            } else {
                log.info("Post参数：" + body);
                Map paramss = new HashMap();
                paramss = (Map) JSON.parse(body);

                for(Object key: paramss.keySet()){
                    String value = paramss.get(key)+"";
                    if(StringUtils.isNotEmpty(value)){
                        params.put(key,paramss.get(key));
                    }
                }
            }

            /** 生成服务端签名 */
            String serverSign = GenerateSignature(params, timestamp);

            /** 如果客户端的签名 和 服务端的签名一致 则验证通过 */
            if (serverSign.equals(sign)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 服务端生成签名方法
     *
     * @param params
     * @param timestamp
     * @return
     * @date 2019/7/11 13:41
     * @author shihx
     */
    public String GenerateSignature(Map<String, Object> params, Long timestamp) {
        StringBuffer sb = new StringBuffer("timeStamp=" + timestamp);
        if (params != null && params.size() > 0) {
            Map<String, Object> sortMapByKey = SortMap.sortMapByKey(params);
            for (Map.Entry<String, Object> entry : sortMapByKey.entrySet()) {
                sb.append("&");
                sb.append(entry.getKey());
                sb.append("=");
                sb.append(entry.getValue());
            }
        }
        sb.append("&secret=");
        sb.append(guoRuanConfig.getSecretKey());
        log.info("服务端 SIGN 签名：" + sb.toString());

//        String sign = Base64Util.encode(MD5Util.encode(sb.toString()));
        String sign = CryptUtils.GetMD5Code(Base64Util.encode(sb.toString()).replaceAll(" ", ""));
        System.out.println(sb.toString());
        System.out.println(Base64Util.encode(sb.toString()).replaceAll(" ", ""));
        log.info("服务端 SIGN 签名：" + sign);
        return sign;
    }


}
